package queue

import "sync/atomic"

/*
 * 使用标志位判断
 * ArrayQueue is a one producer and one consumer queue
 * without locks.
 */

type arrayQueueNode struct {
	data interface{}
	flag uint32
}

type ArrayQueue struct {
	_padding0  [64]byte
	size       uint32
	capMod     uint32
	_padding1  [64]byte
	records    []*arrayQueueNode
	_padding2  [64]byte
	readIndex  uint32
	_padding3  [64]byte
	writeIndex uint32
}

func NewArrayQueue(capaciity uint32) *ArrayQueue {
	q := new(ArrayQueue)
	q.size = RoundUp(capaciity)
	q.capMod = q.size - 1
	q.records = make([]*arrayQueueNode, q.size)
	for i := uint32(0); i < q.size; i++ {
		q.records[i] = &arrayQueueNode{}
	}
	return q
}

func (m *ArrayQueue) Write(value interface{}) bool {
	n := m.records[m.writeIndex]
	if 1 == atomic.LoadUint32(&n.flag) {
		return false
	}
	n.data = value
	n.flag = 1

	m.writeIndex = (m.writeIndex + 1) & m.capMod
	return true
}

func (m *ArrayQueue) Read() (interface{}, bool) {
	n := m.records[m.readIndex]
	if 0 == atomic.LoadUint32(&n.flag) {
		return nil, false
	}

	v := n.data
	n.flag = 0
	n.data = nil

	m.readIndex = (m.readIndex + 1) & m.capMod
	return v, true
}

func (m *ArrayQueue) IsEmpty() bool {
	n := m.records[m.readIndex]
	if 0 == atomic.LoadUint32(&n.flag) {
		return true
	}
	return false
}

func (m *ArrayQueue) IsFull() bool {
	return atomic.LoadUint32(&m.writeIndex) == atomic.LoadUint32(&m.readIndex)
}

func (m *ArrayQueue) Count() uint32 {
	w := atomic.LoadUint32(&m.writeIndex)
	r := atomic.LoadUint32(&m.readIndex)
	if w >= r {
		return w - r
	} else {
		return m.size - r + w
	}
}

func (m *ArrayQueue) Capacity() uint32 {
	return m.size - 1
}
